package org.appfuse.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.Version;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.compass.annotations.Searchable;
import org.compass.annotations.SearchableComponent;
import org.compass.annotations.SearchableId;
import org.compass.annotations.SearchableProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
@Table(name="app_user")
@Searchable
@XmlRootElement
public class User extends BaseObject
  implements Serializable, UserDetails
{
  private static final long serialVersionUID = 3832626162173359411L;
  private Long id;
  private String username;
  private String password;
  private String confirmPassword;
 // private String passwordHint;
  private String firstName;
  private String middleName;
  private String lastName;
  private String email;
  private String phoneNumber;
  private String cellPhone;
  private String language;
 // private String website;
  private Address address = new Address();
  private Integer version;
  private Set<Role> roles = new HashSet();
  private boolean enabled;
  private boolean accountExpired;
  private boolean accountLocked;
  private boolean credentialsExpired;

  public User()
  {
  }

  public User(String username)
  {
    this.username = username; } 
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  @SearchableId
  public Long getId() { return this.id; } 
  @Column(nullable=false, length=50, unique=true)
  @SearchableProperty
  public String getUsername() {
    return this.username;
  }
  @Column(nullable=false)
  @XmlTransient
  public String getPassword() { return this.password; } 
  @Transient
  @XmlTransient
  public String getConfirmPassword() { return this.confirmPassword; } 
//  @Column(name="password_hint")
  @XmlTransient
 /* public String getPasswordHint() {
    return this.passwordHint;
  }*/
  @Column(name="first_name", nullable=false, length=50)
  @SearchableProperty
  public String getFirstName() { return this.firstName; } 
  @Column(name="last_name", nullable=false, length=50)
  @SearchableProperty
  public String getLastName() {
    return this.lastName;
  }
  @Column(nullable=false, unique=true)
  @SearchableProperty
  public String getEmail() { return this.email; } 
  @Column(name="phone_number")
  @SearchableProperty
  public String getPhoneNumber() {
    return this.phoneNumber;
  }
  @SearchableProperty
 // public String getWebsite() {
 //   return this.website;
 // }

  @Transient
  public String getFullName()
  {
    return this.firstName + ' ' + this.lastName;
  }
  @Embedded
  @SearchableComponent
  public Address getAddress() { return this.address;
  }

  @ManyToMany(fetch=FetchType.EAGER)
  @JoinTable(name="user_role", joinColumns={@javax.persistence.JoinColumn(name="user_id")}, inverseJoinColumns={@javax.persistence.JoinColumn(name="role_id")})
  public Set<Role> getRoles()
  {
    return this.roles;
  }

  @Transient
  public List<LabelValue> getRoleList()
  {
    List userRoles = new ArrayList();

    if (this.roles != null) {
      for (Role role : this.roles)
      {
        userRoles.add(new LabelValue(role.getName(), role.getName()));
      }
    }

    return userRoles;
  }

  public void addRole(Role role)
  {
    getRoles().add(role);
  }

  @Transient
  public Set<GrantedAuthority> getAuthorities()
  {
    Set authorities = new LinkedHashSet();
    authorities.addAll(this.roles);
    return authorities;
  }
  @Version
  public Integer getVersion() {
    return this.version;
  }
  @Column(name="account_enabled")
  public boolean isEnabled() {
    return this.enabled;
  }
  @Column(name="account_expired", nullable=false)
  public boolean isAccountExpired() {
    return this.accountExpired;
  }

  @Transient
  public boolean isAccountNonExpired()
  {
    return !isAccountExpired();
  }
  @Column(name="account_locked", nullable=false)
  public boolean isAccountLocked() {
    return this.accountLocked;
  }

  @Transient
  public boolean isAccountNonLocked()
  {
    return !isAccountLocked();
  }
  @Column(name="credentials_expired", nullable=false)
  public boolean isCredentialsExpired() {
    return this.credentialsExpired;
  }

  @Transient
  public boolean isCredentialsNonExpired()
  {
    return !this.credentialsExpired;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public void setPassword(String password) {
    this.password = password;
  }

  public void setConfirmPassword(String confirmPassword) {
    this.confirmPassword = confirmPassword;
  }

 /* public void setPasswordHint(String passwordHint) {
    this.passwordHint = passwordHint;
  }*/

  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }

  public void setLastName(String lastName) {
    this.lastName = lastName;
  }

  public void setEmail(String email) {
    this.email = email;
  }

  public void setPhoneNumber(String phoneNumber) {
    this.phoneNumber = phoneNumber;
  }

 /* public void setWebsite(String website) {
    this.website = website;
  }*/

  public void setAddress(Address address) {
    this.address = address;
  }

  public void setRoles(Set<Role> roles) {
    this.roles = roles;
  }

  public void setVersion(Integer version) {
    this.version = version;
  }

  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }

  public void setAccountExpired(boolean accountExpired) {
    this.accountExpired = accountExpired;
  }

  public void setAccountLocked(boolean accountLocked) {
    this.accountLocked = accountLocked;
  }

  public void setCredentialsExpired(boolean credentialsExpired) {
    this.credentialsExpired = credentialsExpired;
  }

  public boolean equals(Object o)
  {
    if (this == o) {
      return true;
    }
    if (!(o instanceof User)) {
      return false;
    }

    User user = (User)o;

    return this.username != null ? this.username.equals(user.getUsername()) : user.getUsername() == null;
  }

  public int hashCode()
  {
    return this.username != null ? this.username.hashCode() : 0;
  }

  public String toString()
  {
    ToStringBuilder sb = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE).append("username", this.username).append("enabled", this.enabled).append("accountExpired", this.accountExpired).append("credentialsExpired", this.credentialsExpired).append("accountLocked", this.accountLocked);
    int i;
    if (this.roles != null) {
      sb.append("Granted Authorities: ");

      i = 0;
      for (Role role : this.roles) {
        if (i > 0) {
          sb.append(", ");
        }
        sb.append(role.toString());
        i++;
      }
    } else {
      sb.append("No Granted Authorities");
    }
    return sb.toString();
  }
  
  @Column(name="cell_phone", nullable=true, length=50)
  @SearchableProperty
  public String getCellPhone() {
	return this.cellPhone;
}

public void setCellPhone(String cellPhone) {
	this.cellPhone = cellPhone;
}

@Column(name="language", nullable=false, length=50)
@SearchableProperty
public String getLanguage() {
	return this.language;
}

public void setLanguage(String language) {
	this.language = language;
}

@Column(name="middle_name", nullable=false, length=50)
@SearchableProperty
public String getMiddleName() {
	return this.middleName;
}

public void setMiddleName(String middleName) {
	this.middleName = middleName;
}
}